`timescale 1ns/100ps

`include "sim_glb.sv"

module tc;

localparam          DATA_BW                 = 18;
localparam          SYNC_NUM_D2S            = 3;
localparam          SYNC_NUM_S2D            = 3;
localparam          DATA_NUM                = 20_000;

reg                                         rst_src_n;
reg                                         clk_src;

reg                                         src_vld;
reg                 [DATA_BW-1:0]           src_data;
wire                                        src_rdy;

reg                                         rst_dst_n;
reg                                         clk_dst;

wire                                        dst_vld;
wire                [DATA_BW-1:0]           dst_data;
reg                                         dst_rdy;

initial begin:CRG
    rst_src_n=1'b0;
    clk_src=1'b0;
    rst_dst_n=1'b0;
    clk_dst=1'b0;

    fork
        rst_src_n=#100.5 1'b1;
        rst_dst_n=#100.5 1'b1;

        forever clk_src=#4 ~clk_src;
        forever clk_dst=#5 ~clk_dst;
    join
end

RGRS_MNG    rgrs;
initial begin:REGRESS
    rgrs = new("tc_sync_bus", 2);

    rgrs.wait_chks_done(100_000_000);
end

initial begin:GEN_SRC
    reg [DATA_BW-1:0]   gen_data;
    integer             gap;

    src_vld  = 1'b0;
    src_data = 0;
    gen_data = 0;

    @(posedge rst_src_n);

    @(posedge clk_src);
    repeat(DATA_NUM) begin
        gap = $urandom_range(0, 20);
        repeat(gap) begin
            @(posedge clk_src);
        end

        src_vld  =`U_DLY 1'b1;
        src_data =`U_DLY gen_data;
        @(posedge clk_src);
        while(src_rdy==1'b0) begin
            @(posedge clk_src);
        end

        src_vld  =`U_DLY 1'b0;
        gen_data = gen_data + 1;
    end
    rgrs.one_chk_done("src is done.");
end

sync_bus #(
        .DATA_BW                        (DATA_BW                        ),
        .SYNC_NUM_D2S                   (SYNC_NUM_D2S                   ),
        .SYNC_NUM_S2D                   (SYNC_NUM_S2D                   )
) u_sync_bus ( 
        .rst_src_n                      (rst_src_n                      ),
        .clk_src                        (clk_src                        ),

        .src_vld                        (src_vld                        ),
        .src_data                       (src_data                       ),
        .src_rdy                        (src_rdy                        ),

        .rst_dst_n                      (rst_dst_n                      ),
        .clk_dst                        (clk_dst                        ),

        .dst_vld                        (dst_vld                        ),
        .dst_data                       (dst_data                       ),
        .dst_rdy                        (dst_rdy                        )
);

initial begin:CHK_DST
    reg [DATA_BW-1:0]   chk_data;

    chk_data = 0;

    @(posedge rst_dst_n);

    repeat(DATA_NUM) begin
        @(posedge clk_dst);
        while((dst_vld==1'b0) || (dst_rdy==1'b0)) begin
            @(posedge clk_dst);
        end

        if (dst_data!=chk_data) begin
            $error("dst_data %h is not expected %h", dst_data, chk_data);
            $stop;
        end
        chk_data = chk_data + 1;
    end
    rgrs.one_chk_done("chk is done.");
end

always@(posedge clk_dst or negedge rst_dst_n) begin
    if (rst_dst_n==1'b0) begin
        dst_rdy <=`U_DLY 1'b0;
    end else begin
        dst_rdy <=`U_DLY ($urandom_range(1, 100)<=20) ? 1'b1 : 1'b0;
    end
end

endmodule

